package com.github.kaelthasbmg;

import com.github.kaelthasbmg.bean.DataBaseDefine;
import com.github.kaelthasbmg.factory.analyse.Analyser;
import com.github.kaelthasbmg.factory.analyse.AnalyserFactory;
import com.github.kaelthasbmg.factory.generate.Generator;
import com.github.kaelthasbmg.factory.generate.GeneratorFactory;
import com.github.kaelthasbmg.utils.StringUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Properties;

/**
 * 数据库结构及数据转换类
 */
public final class Transfer {
    private static Logger logger = LoggerFactory.getLogger(Transfer.class);

    /**
     * 转换处理
     * @param args
     */
    public static void main(String[] args) {
        try {
            logger.info("开始读取配置文件");
            Map<String, String> settingMap = getSetting();
            logger.info("配置文件读取完毕，配置信息：{}", StringUtil.toString(settingMap));

            logger.info("开始连接至数据库");
            try(
                Connection sourceConnection = getSourceConnection(settingMap);
                Connection targetConnection = getTargetConnection(settingMap)
            ) {
                logger.info("成功连接至数据库");

                logger.info("开始获取源数据库结构定义");
                Analyser analyser = AnalyserFactory.getInstance(sourceConnection);
                DataBaseDefine dataBaseDefine = analyser.getDataBaseDefine(sourceConnection);
                logger.info("源数据库结构定义获取完毕");

                logger.info("开始构造目标数据库结构");
                Generator generator = GeneratorFactory.getInstance(targetConnection, dataBaseDefine);
                generator.generateStructure();
                logger.info("目标数据库结构构造完成");

            } catch (Throwable e) {
                throw e;
            }
        } catch (Throwable e) {
            logger.error("转换数据库失败", e);
        }
    }

    /**
     * 创建目标数据库连接
     * @param settingMap 配置信息
     * @return 数据库连接
     * @throws ClassNotFoundException
     * @throws SQLException
     * @throws InstantiationException
     * @throws IllegalAccessException
     */
    private static Connection getTargetConnection(Map<String, String> settingMap) throws ClassNotFoundException, SQLException, InstantiationException, IllegalAccessException {
        String driverClass = settingMap.get("target.driverClass");
        String url = settingMap.get("target.data.url");
        String userName = settingMap.get("target.user.name");
        String password = settingMap.get("target.user.password");

        return getConnection(driverClass, url, userName, password);
    }

    /**
     * 创建源数据库连接
     * @param settingMap 配置信息
     * @return 数据库连接
     * @throws ClassNotFoundException
     * @throws SQLException
     * @throws InstantiationException
     * @throws IllegalAccessException
     */
    private static Connection getSourceConnection(Map<String, String> settingMap) throws ClassNotFoundException, SQLException, InstantiationException, IllegalAccessException {
        String driverClass = settingMap.get("source.driverClass");
        String url = settingMap.get("source.data.url");
        String userName = settingMap.get("source.user.name");
        String password = settingMap.get("source.user.password");

        return getConnection(driverClass, url, userName, password);
    }

    /**
     * 获取数据库连接
     * @param driverClass 驱动名称
     * @param url 连接地址
     * @param userName 连接用户名
     * @param password 连接密码
     * @return 数据库连接
     * @throws ClassNotFoundException
     * @throws IllegalAccessException
     * @throws InstantiationException
     * @throws SQLException
     */
    private static Connection getConnection(String driverClass, String url, String userName, String password) throws ClassNotFoundException, IllegalAccessException, InstantiationException, SQLException {
        Class.forName(driverClass).newInstance();
        return DriverManager.getConnection(url, userName, password);
    }

    /**
     * 获取配置
     * @return 配置信息
     */
    private static Map<String, String> getSetting() {
        Map<String, String> settingMap = new HashMap<>();

        try (InputStream inputStream = Transfer.class.getClassLoader().getResourceAsStream("jdbc.properties")) {

            Properties settingProperties = new Properties();
            settingProperties.load(inputStream);

            Iterator<Object> keyIterator = settingProperties.keySet().iterator();
            Object key = null;
            while (keyIterator.hasNext()) {
                key = keyIterator.next();

                if (key != null) {
                    settingMap.put(key.toString(), settingProperties.getProperty(key.toString()));
                }
            }

            return settingMap;
        } catch (Throwable e) {
            throw new RuntimeException(e);
        }
    }
}
